package top.smallway.bs_vr.Arranges;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.google.firebase.crashlytics.buildtools.reloc.org.apache.commons.io.IOUtils;

import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.generic.GenericAudioHeader;
import org.jaudiotagger.audio.ogg.util.OggInfoReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {
    static List<Message> message = new ArrayList<>();

    public static double getAudioDuration(File file) {
        RandomAccessFile randomAccessFile = null;
        try {
            randomAccessFile = new RandomAccessFile(file, "rwd");
            OggInfoReader oggInfoReader = new OggInfoReader();
            GenericAudioHeader read = oggInfoReader.read(randomAccessFile);
            float ret = (float) read.getPreciseLength();
            randomAccessFile.close();
            return ret;
        } catch (CannotReadException | IOException e) {
            e.printStackTrace();
        }
        return 0;
    }


    private static int calculateDurationInSeconds(byte[] audioBytes, long audioSize) {
        // Calculate duration based on audio file bytes and size
        return 0;
    }

    public static Map<String, Double> classifySongs(String baseDir) {
        Map<String, Double> songMap = new HashMap<>();
        File dir = new File(baseDir);
        if (!dir.isDirectory()) {
            return songMap;
        }

        File[] songFolders = dir.listFiles();
        for (File songFolder : songFolders) {
            String infoPath = songFolder.getAbsolutePath() + "/info.dat";
            File infoFile = new File(infoPath);
            if (!infoFile.exists()) {
                infoPath = songFolder.getAbsolutePath() + "/Info.dat";
                infoFile = new File(infoPath);
                if (!infoFile.exists()) {
                    continue;
                }
            }

            String jsonString = readJsonFile(infoFile);
            JSONObject infoObject = JSONObject.parseObject(jsonString, Feature.OrderedField);
            String songName = infoObject.getString("_songName");
            String songAuthor = infoObject.getString("_songAuthorName");
            int bpm = infoObject.getIntValue("_beatsPerMinute");

            String audioPath = songFolder.getAbsolutePath() + "/" + infoObject.getString("_songFilename");
            double audioDuration = getAudioDuration(new File(audioPath));

            File[] beatmapFiles = songFolder.listFiles((dir1, name) -> name.endsWith(".dat") && !name.equals("info.dat") && !name.equals("Info.dat"));
            int maxBlocks = 0;
            for (File beatmapFile : beatmapFiles) {
                int totalBlocks = getBlockAndTime(beatmapFile, bpm);
                if (totalBlocks > maxBlocks) {
                    maxBlocks = totalBlocks;
                }
            }

            double speed = maxBlocks / audioDuration;
            songMap.put(songName + " - " + songAuthor, speed);
            moveSongToFolder(String.valueOf(songFolder), (int) speed);
        }

        return songMap;
    }

    private static String readJsonFile(File file) {
        FileInputStream fis;
        try {
            fis = new FileInputStream(file);
            return IOUtils.toString(fis, "UTF-8");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static int getBlockAndTime(File beatmapFile, int bpm) {
        String jsonString = readJsonFile(beatmapFile);
        JSONObject beatmapObject = JSONObject.parseObject(jsonString);

        String version = beatmapObject.getString("version");
        if (version == null) {
            version = beatmapObject.getString("_version");
            if (version == null) {
                version = "2.0.0";
            }
        }

        if (!beatmapObject.containsKey("_notes") && !beatmapObject.containsKey("colorNotes")) {
            return 0;
        }
        String string="已分析——"+beatmapFile;
        message.add(new Message(string));

        String noteKey = version.startsWith("2.") ? "_notes" : "colorNotes";

        JSONArray notesArray = beatmapObject.getJSONArray(noteKey);
        int totalBlocks = 0;
        for (int i = 0; i < notesArray.size(); i++) {
            JSONObject noteObject = notesArray.getJSONObject(i);
            int type = version.startsWith("2.") ? noteObject.getIntValue("_type") : noteObject.getIntValue("c");
            if (type == 0 || type == 1 || type == 2) {
                totalBlocks++;
            }
        }

        return totalBlocks;
    }

    public static void moveSongToFolder(String songPath, int speed) {
        int maxSongs = 50;
        // 根据速度决定要移动到哪个文件夹
        int speedCategory = Math.min(speed, 12);
        String speedFolderName = Integer.toString(speedCategory);
        if (speedCategory >= 12) {
            speedFolderName = "12+";
        }
        File songFile = new File(songPath);
        String targetFolder = new File(songFile.getParent(), speedFolderName).getPath();

        // Check how many songs already exist in the folder
        int subfolderCounter = 1;
        String currentTargetFolder = targetFolder;
        while (new File(currentTargetFolder).exists() && new File(currentTargetFolder).list().length >= maxSongs) {
            subfolderCounter++;
            currentTargetFolder = targetFolder + "-" + subfolderCounter;
        }

        // If the target folder doesn't exist, create it
        File targetFolderFile = new File(currentTargetFolder);
        if (!targetFolderFile.exists()) {
            targetFolderFile.mkdirs();
        }

        // Move song file
        String targetPath = new File(targetFolderFile, songFile.getName()).getPath();
        // 如果文件存在则移动到"已存在"文件夹
        if (!new File(targetPath).exists()) {
            try {
                Files.move(songFile.toPath(), new File(targetPath).toPath(), StandardCopyOption.REPLACE_EXISTING);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            String existedFolder = new File(songFile.getParent(), "已存在").getPath();
            File existedFolderFile = new File(existedFolder);
            if (!existedFolderFile.exists()) {
                existedFolderFile.mkdirs();
            }
            try {
                Files.move(songFile.toPath(), new File(existedFolderFile, songFile.getName()).toPath(), StandardCopyOption.REPLACE_EXISTING);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static List<Message> main(String baseDir) {
        Map<String, Double> songMap = classifySongs(baseDir);
        message.add(new Message("正在分析曲包中......"));
        for (String songInfo : songMap.keySet()) {
            String string="分析完成："+songInfo + " - 速度: " + songMap.get(songInfo);
            message.add(new Message(string));
            System.out.println(songInfo + " - Speed: " + songMap.get(songInfo));
        }
        message.add(new Message("已按照速度完成分类"));
        return message;
    }
}
